﻿using MiniFox.Caching;
using MiniFox.Components;
using MiniFox.Infrastructure;
using MiniFox.Platform.Configurations;
using MiniFox.Platform.Exceptions;
using MiniFox.Platform.Models;
using MiniFox.Platform.Providers;
using MiniFox.Platform.Resources;
using MiniFox.Utility;

namespace MiniFox.Platform.Services
{
    /// <summary>
    /// 
    /// </summary>
    public class PinCodeService : Component, IPinCodeService
    {
        const string CACHE_KEY = "PinCodeContext";
        /// <summary>
        /// 
        /// </summary>
        [AutoConfigure]
        protected PinCodeConfiguration PinCodeConfig
        {
            get;
            set;
        }
        /// <summary>
        /// 
        /// </summary>
        [AutoWired]
        protected IPinCodeProvider Provider
        {
            get;
            set;
        }
        #region 短信验证码
        /// <summary>
        /// 根据邮箱或手机号创建并发送pincode，成功后返回票据
        /// </summary>
        /// <param name="signName">账号名</param>
        /// <param name="ipAddress">接入方ip</param>
        /// <returns></returns>
        public virtual PincodeContext CreatePincodeContext(string signName, string ipAddress)
        {
            if (string.IsNullOrEmpty(signName))
            {
                throw new MiniFox.Exceptions.SystemException(ResMessage.ERR_InvalidSignName);
            }
            var key = $"{CACHE_KEY}-{signName}";
            var context = CacheService.GetCacheObject<PincodeContext>(key);
            if (context == null || context.Ticket.IsExpired())
            {
                string pinCode = Tools.GenerateRandomCode(PinCodeConfig.CodeLen, PinCodeConfig.CodeType);
                var ticket = new Ticket(SequenceGUID.NewGUID(), PinCodeConfig.TicketExpiration);
                context = new PincodeContext
                {
                    SignName = signName,
                    PinCode = pinCode,
                    Ticket = ticket,
                    IpAddress = ipAddress,
                    CodeExpiration = PinCodeConfig.CodeExpiration
                };
                if (Provider.SendPinCode(context))
                    CacheService.AddCacheObject(key, context, PinCodeConfig.TicketExpiration);
            }
            else
            {
                throw new MiniFox.Exceptions.SystemException(ResMessage.MSG_CircuitBreak);
            }

            return context;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="ticket"></param>
        /// <param name="code"></param>
        /// <param name="ipAddress"></param>
        /// <returns></returns>
        public virtual bool MatchPinCode(Ticket ticket, string code, string ipAddress)
        {
            if (!ticket.IsExpired())
                throw new PlatformException(ResMessage.ERR_InvalidTicket);
            PincodeContext context = Provider.GetPinCodeContext(ticket);
            if (context.IpAddress != ipAddress)
                throw new PlatformException(ResMessage.ERR_UnknownApiClient);

            return context.PinCode == code;
        }
        #endregion
    }
}
